#include "headfiles.h"
#include <stdlib.h>

using namespace std;

// Print binary format of numbers
// Print binary format of numbers
bool printNumberBinaries(const char *num_str,
                         string &bin_str) {
    if (num_str == NULL) {
        cout << "Input string is NULL!" << endl;
        return false;
    }

    string str(num_str);
    size_t loc = str.find('.');
    size_t str_size = str.size();

    int int_part = 0;
    double dec_part = 0.0;
    // If no point in the number, then it is an interger
    if (loc == string::npos) {
        int_part = atoi(str.c_str());
    }
    else {
        string int_str = str.substr(0, loc);
        int_part = atoi(int_str.c_str());
        string dec_str = str.substr(loc, str_size - loc);
        dec_part = strtod(dec_str.c_str(), NULL);
    }

    // Process the integer part
    // Add a 1 as the prefix if integer is less than 0
    // otherwise, prefix is 0
    bool minus_flag = false;
    if (int_part < 0) {
        int_part = (-1) * int_part;
        minus_flag = true;
    }

    while (int_part > 0) {
        int bit = int_part & 1;
        int_part >>= 1;
        if (bit) {
            bin_str = "1" + bin_str;
        }
        else {
            bin_str = "0" + bin_str;
        }
    }

    if (minus_flag) {
        bin_str = "1" + bin_str;
    }
    else {
        bin_str = "0" + bin_str;
    }

    string out_dec_str;
    // Process the decimal part
    while (dec_part > 0.0) {
        dec_part *= 2;
        int bit = 0;
        if (dec_part >= 1.0) {
            bit = 1;
            dec_part -= 1;
        }

        if (bit) {
            out_dec_str = out_dec_str + "1";
        }
        else {
            out_dec_str = out_dec_str + "0";
        }

        if (out_dec_str.size() > 32) {
            cout << "Error" << endl;
            break;
        }
    }

    bin_str = bin_str + "." + out_dec_str;

    return true;
}


unsigned swapBits(unsigned int val) {
    unsigned int ret_val;
    ret_val = val & (0xAAAAAAAA);
    ret_val >>= 1;
    val = val & (0x55555555);
    val <<= 1;
    ret_val |= val;

    return ret_val;
}

bool calcIntWithSameBitOnes(unsigned int val, 
                            unsigned int &small_neighbor,
                            unsigned int &big_neighbor) {


    //For the largest number that is smaller than val.
    //Find the first bit 1 that has a 0 on its right side, 
    //exchange the bit 1 and 0. Then move all the bit 1s 
    //on its right side to as left as possible
    unsigned int tmp_val = val;
    size_t bit_one_num = 0, bit_one_loc;
    unsigned int mask;
    unsigned int max_uint = 0xFFFFFFFF;
    unsigned int ret_val;
    bool hit_zero_flag = false;
    size_t bit_num = sizeof(unsigned int) * 8;
    size_t i;
    for (i = 0; i < bit_num; i++) {
        if ((tmp_val & 1) == 0) {
            hit_zero_flag = true;
        }
        else {
            if (hit_zero_flag) {
                bit_one_loc = i;
                break;
            }
            ++bit_one_num;
        }
        tmp_val >>= 1;
    }

    if (i == bit_num) {
        cout << "Cannot find the bigger number that is smaller than " << val << endl;
    }
    else {
        // right shift the bit 1 at bit_one_loc by 1. 
        mask = 1;
        // covert 0 at bit_one_loc - 1 to 1
        mask = mask << (bit_one_loc - 1);
        ret_val = val | mask;
        
        // convert 1 at bit_one_loc to 0
        mask <<= 1;
        mask = ~mask;
        ret_val = ret_val & mask;

        // Move all the bit 1s to as left as possible
        // Clear all the bit 1s after bit_one_loc - 1
        mask = 1;
        mask = (mask << (bit_one_loc - 1)) - 1;
        mask = ~mask;
        ret_val = ret_val & mask;

        // construct a number with bit_one_num bit 1s and those
        // bit 1s as left as possible (but should be at the right 
        // side of bit_one_loc - 1
        mask = 1;
        mask = (mask << bit_one_num) - 1;
        mask <<= (bit_one_loc - 1 - bit_one_num);
        ret_val = ret_val | mask;
        small_neighbor = ret_val;
    }

    // Calc the smallest number that is bigger than val
    bool hit_one_flag = false;
    size_t bit_zero_loc;
    bit_one_num = 0;
    tmp_val = val;
    for (i = 0; i < bit_num; i++) {
        if ((tmp_val & 1) == 1) {
            hit_one_flag = true;
            ++bit_one_num;
        }
        else {
            if (hit_one_flag) {
                bit_zero_loc = i;
                break;
            }
        }
        tmp_val >>= 1;
    }

    if (bit_zero_loc == bit_num) {
        cout << "Cound find the smallest number that is larger than " << val << endl;
    }
    else {
        // Left shift the bit 1 by 1
        mask = 1 << (bit_zero_loc);
        ret_val = val | mask;

        mask >>= 1;
        mask = ~mask;
        ret_val = ret_val & mask;

        // Move all the bit right to loc bit_zero_loc - 1 to as right as possible
        mask = (1 << (bit_zero_loc - 1)) - 1;
        mask = ~mask;
        ret_val &= mask;

        mask = (1 << (bit_one_num - 1)) - 1;
        ret_val |= mask;
        big_neighbor = ret_val;
    }
}

unsigned calcBitDistance(unsigned int val1, 
                         unsigned int val2) {

    unsigned int dist = val1 ^ val2;
    int dist_num = 0;
    while (dist) {
        dist = dist & (dist - 1);
        ++dist_num;
    }

    return dist_num;
}

unsigned int replaceIntegerBits(unsigned int n,
								unsigned int m,
								unsigned int start, 
								unsigned int end) {
	unsigned int mask1 = 2^(end - start + 2) - 1;
	mask1 = mask1 << start;
	mask1 = ~mask1;

	n = n & mask1;
	unsigned int m_shift = m << start;
	n = n | m_shift;

	return n;
}

